package com.sc.nft.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sc.nft.dao.MallUserPropsReleasedDetailDao;
import com.sc.nft.entity.DaoPropsReleasedConfig;
import com.sc.nft.entity.EquityProps;
import com.sc.nft.entity.MallUserPropsReleasedDetail;
import com.sc.nft.entity.MallUserPropsRewards;
import com.sc.nft.entity.UserCollection;
import com.sc.nft.entity.UserInfo;
import com.sc.nft.entity.dto.ReleaseDTO;
import com.sc.nft.entity.vo.UserPropsReleasedDetailVO;
import com.sc.nft.enums.UserEquityPropsGetTypeEnum;
import com.sc.nft.service.DaoPropsReleasedConfigService;
import com.sc.nft.service.EquityPropsService;
import com.sc.nft.service.MallUserPropsReleasedDetailService;
import com.sc.nft.service.MallUserPropsRewardsService;
import com.sc.nft.service.UserCollectionService;
import com.sc.nft.service.UserEquityPropsService;
import com.sc.nft.service.UserInfoService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class MallUserPropsReleasedDetailServiceImpl implements MallUserPropsReleasedDetailService {


    private final MallUserPropsReleasedDetailDao mallUserPropsReleasedDetailDao;
    private final UserInfoService userInfoService;
    private final EquityPropsService equityPropsService;
    private final DaoPropsReleasedConfigService daoPropsReleasedConfigService;
    private final MallUserPropsRewardsService mallUserPropsRewardsService;
    private final UserCollectionService userCollectionService;
    private final UserEquityPropsService userEquityPropsService;
    private static final int PAGE_SIZE = 1000; // 每页记录数
    private static final int THREAD_COUNT = 5;

    @Override
    public void propsReleasedTask(Date date, Boolean isSpecifyDate) {
        long startTimeMillis = System.currentTimeMillis(); // 记录开始时间
        log.info("开始执行道具释放任务，参数：{}", JSON.toJSONString(date));
        // 设置时间范围
        Date startTime = DateUtils.truncate(date, Calendar.DATE); // 获取当天0点
        Date endTime = DateUtils.addMilliseconds(DateUtils.ceiling(date, Calendar.DATE), -1); // 获取当天23:59:59

        ExecutorService executorService = Executors.newFixedThreadPool(THREAD_COUNT);

        Long lastMinId = Long.MAX_VALUE;

        while (true) {
            List<MallUserPropsRewards> records = mallUserPropsRewardsService.selectByLastMinId(lastMinId, PAGE_SIZE, isSpecifyDate ? startTime : null);
            if (records.isEmpty()) {
                break;
            }

            lastMinId = records.get(records.size() - 1).getId();

            for (MallUserPropsRewards userPropsRewards : records) {
                executorService.submit(() -> release(userPropsRewards, startTime, endTime));
            }
        }
        executorService.shutdown();
        try {
            if (!executorService.awaitTermination(1, TimeUnit.HOURS)) {
                executorService.shutdownNow();
            }
        } catch (InterruptedException e) {
            executorService.shutdownNow();
        }
        long endTimeMillis = System.currentTimeMillis(); // 记录结束时间
        long duration = endTimeMillis - startTimeMillis; // 计算耗时
        log.info("道具释放任务执行完毕，耗时：{} 毫秒", duration);
    }

    @Transactional(rollbackFor = Exception.class)
    public void release(MallUserPropsRewards userPropsRewards, Date startTime, Date endTime) {
        long startTimeMillis = System.currentTimeMillis(); // 记录开始时间
        log.info("开始单个执行道具释放，参数：{}", JSON.toJSONString(userPropsRewards));
        Long daoId = userPropsRewards.getDaoId();
        Long userId = userPropsRewards.getUserId();
        Long propsId = userPropsRewards.getPropsId();
        DaoPropsReleasedConfig daoPropsReleasedConfig = daoPropsReleasedConfigService.getDaoPropsReleasedConfig(daoId);
        if (daoPropsReleasedConfig == null) {
            return;
        }
        //判断开始时间
        if (daoPropsReleasedConfig.getInitialReleaseTime() != null && daoPropsReleasedConfig.getInitialReleaseTime().after(new Date())) {
            return;
        }
        //判断上次释放时间
        Integer releasePeriod = daoPropsReleasedConfig.getReleasePeriod();
        MallUserPropsReleasedDetail lastReleasedDetail = mallUserPropsReleasedDetailDao.getLastReleasedDetail(userId, propsId, daoId);
        if (lastReleasedDetail != null) {
            // 截断到天
            Date lastReleaseDate = DateUtils.truncate(lastReleasedDetail.getCreateTime(), Calendar.DATE);
            Date currentDate = DateUtils.truncate(startTime, Calendar.DATE);

            long daysSinceLastRelease = (currentDate.getTime() - lastReleaseDate.getTime()) / (1000 * 60 * 60 * 24);
            if (daysSinceLastRelease < releasePeriod) {
                log.info("道具{}在{}天内已释放，跳过本次释放", propsId, releasePeriod);
                return; // 如果未达到释放周期，直接返回
            }
        }
        //剩余释放数
        Integer remainingRewards = userPropsRewards.getCreditedNum() - userPropsRewards.getReleasedNum();
        if (remainingRewards <= 0) {
            return;
        }
        // 检查是否达到门槛值
        if (daoPropsReleasedConfig.getReleaseLimitEnabled() && remainingRewards < daoPropsReleasedConfig.getMinItemsToRelease()) {
            return;
        }
        // 判断今天是否已释放
        LambdaQueryWrapper<MallUserPropsReleasedDetail> todayWrapper = new LambdaQueryWrapper<>();
        todayWrapper.eq(MallUserPropsReleasedDetail::getUserId, userId)
                .eq(MallUserPropsReleasedDetail::getPropsId, propsId)
                .eq(MallUserPropsReleasedDetail::getDaoId, daoId)
                .ge(MallUserPropsReleasedDetail::getCreateTime, startTime)
                .lt(MallUserPropsReleasedDetail::getCreateTime, endTime);
        Integer count = mallUserPropsReleasedDetailDao.count(todayWrapper);
        if (count > 0) {
            log.info("用户{}的道具{}今天已释放过，跳过处理", userId, propsId);
            return;
        }

        List<ReleaseDTO> releaseDTOList = JSON.parseArray(daoPropsReleasedConfig.getReleaseJson(), ReleaseDTO.class);
        if (CollectionUtils.isEmpty(releaseDTOList)) {
            return;
        }
        List<Long> collectionIdList = releaseDTOList.stream().map(release -> release.getCollectionId()).distinct().collect(Collectors.toList());


        BigDecimal releaseRate = BigDecimal.ZERO;
        //通过用户的藏品计算释放速率
        List<UserCollection> userCollectionList = userCollectionService.getCollectionIdByUserId(userId, collectionIdList);
        Set<Long> collectionIdSet = null;
        if (CollectionUtil.isNotEmpty(userCollectionList)) {
            collectionIdSet = userCollectionList.stream().map(userCollection -> userCollection.getCollectionId()).collect(Collectors.toSet());
        }

        if (releaseDTOList != null) {
            releaseRate = releaseDTOList.stream()
                    .filter(dto -> dto.getCollectionId() != null && dto.getCollectionId() == -1)
                    .map(ReleaseDTO::getReleaseSpeed)
                    .findFirst()
                    .orElse(BigDecimal.ZERO);  // 如果没找到默认返回0
        }
        if (CollectionUtil.isNotEmpty(collectionIdSet)) {
            for (ReleaseDTO releaseDTO : releaseDTOList) {
                //普通用户或者持有藏品的累加释放速度
                if (collectionIdSet.contains(releaseDTO.getCollectionId())) {
                    releaseRate = releaseRate.add(releaseDTO.getReleaseSpeed());
                }
            }
        }

        Integer releaseNum = calculateReleaseAmount(remainingRewards, releaseRate);

        //保存释放明细
        MallUserPropsReleasedDetail mallUserPropsReleasedDetail = new MallUserPropsReleasedDetail();
        mallUserPropsReleasedDetail.setReleasedNum(releaseNum);
        mallUserPropsReleasedDetail.setDaoId(daoId);
        mallUserPropsReleasedDetail.setUserId(userId);
        mallUserPropsReleasedDetail.setPropsId(propsId);
        mallUserPropsReleasedDetailDao.save(mallUserPropsReleasedDetail);

        //更新道具汇总数据
        MallUserPropsRewards mallUserPropsRewards = new MallUserPropsRewards();
        mallUserPropsRewards.setUserId(userId);
        mallUserPropsRewards.setPropsId(propsId);
        mallUserPropsRewards.setDaoId(daoId);
        mallUserPropsRewards.setReleasedNum(releaseNum);
        mallUserPropsRewardsService.updateByUserIdAndPropsIdAndDaoId(mallUserPropsRewards);

        //发放道具
        EquityProps equityProps = equityPropsService.getById(propsId);
        userEquityPropsService.addEquityPropsByUser(equityProps, userId, UserEquityPropsGetTypeEnum.MALL_REWARD_CONSUMED,
                releaseNum, "消费奖励", userPropsRewards.getId(), BigDecimal.ZERO,
                UserEquityPropsGetTypeEnum.MALL_REWARD_CONSUMED, userPropsRewards.getId());
        long endTimeMillis = System.currentTimeMillis(); // 记录结束时间
        long duration = endTimeMillis - startTimeMillis; // 计算耗时
        log.info("单个道具释放任务执行完毕，耗时：{} 毫秒", duration);
    }

    /**
     * 计算释放数量
     *
     * @param remainingRewards 剩余释放数
     * @param releaseRate      释放速度
     * @return
     */
    public Integer calculateReleaseAmount(Integer remainingRewards, BigDecimal releaseRate) {

        // 计算释放数量
        BigDecimal remainingRewardsBig = BigDecimal.valueOf(remainingRewards);
        BigDecimal releaseAmount = remainingRewardsBig.multiply(releaseRate).divide(BigDecimal.valueOf(10000), RoundingMode.HALF_UP);

        // 确保释放数量至少为1
        if (releaseAmount.compareTo(BigDecimal.ONE) < 0) {
            releaseAmount = BigDecimal.ONE;
        }
        return releaseAmount.intValue();
    }


    @Override
    public Page<UserPropsReleasedDetailVO> page(Long daoId, UserInfo user, Page page) {
        return this.page(daoId, user, null, null, null, page);
    }

    @Override
    public Page<UserPropsReleasedDetailVO> page(Date startTime, Date endTime, String phoneNumber, Page page) {
        return this.page(null, null, startTime, endTime, phoneNumber, page);
    }

    public Page<UserPropsReleasedDetailVO> page(Long daoId, UserInfo user, Date startTime, Date endTime, String phoneNumber, Page page) {
        // 获取用户ID
        Long userId = null;
        if (user != null) {
            userId = user.getId();
        }
        if (StringUtils.isNotBlank(phoneNumber)) {
            UserInfo userInfo = userInfoService.getByUserTel(phoneNumber);
            if (userInfo != null) {
                userId = userInfo.getId();
            } else {
                return new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
            }
        }

        // 构建查询条件
        LambdaQueryWrapper<MallUserPropsReleasedDetail> wrapper = new LambdaQueryWrapper<>();
        wrapper.ge(startTime != null, MallUserPropsReleasedDetail::getModifyTime, startTime)
                .le(endTime != null, MallUserPropsReleasedDetail::getModifyTime, endTime)
                .eq(userId != null, MallUserPropsReleasedDetail::getUserId, userId)
                .eq(daoId != null, MallUserPropsReleasedDetail::getDaoId, daoId)
                // 固定查询已释放状态
                .orderByDesc(MallUserPropsReleasedDetail::getCreateTime);

        // 执行分页查询
        Page<MallUserPropsReleasedDetail> detailPage = mallUserPropsReleasedDetailDao.page(page, wrapper);

        // 转换为VO对象
        Page<UserPropsReleasedDetailVO> voPage = new Page<>(detailPage.getCurrent(), detailPage.getSize(), detailPage.getTotal());
        voPage.setRecords(detailPage.getRecords().stream().map(this::convertToVO).collect(Collectors.toList()));

        return voPage;
    }

    private UserPropsReleasedDetailVO convertToVO(MallUserPropsReleasedDetail detail) {
        UserPropsReleasedDetailVO vo = new UserPropsReleasedDetailVO();
        BeanUtils.copyProperties(detail, vo);

        // 如果需要获取用户手机号
        UserInfo userInfo = userInfoService.getById(detail.getUserId());
        if (userInfo != null) {
            vo.setPhoneNumber(userInfo.getUserTel());
            vo.setNickName(userInfo.getNickName());
        }
        EquityProps equityProps = equityPropsService.getById(detail.getPropsId());
        if (equityProps != null) {
            vo.setPropName(equityProps.getFirstTitle());
            vo.setCreationContent(equityProps.getCreationContent());
        }
        return vo;
    }
}
